// 试想一个函数模板示例:

template <typename T1, typename T2>
void AddTo(T1, T2)
{
    ? ? ? = T1 + T2; // 如果 T1,T2 是两个不同类型的值,那么???应该用什么接受呢
}

// 答案是在C++98 没有添加 decltype 关键字之前,这种问题无解因为没有办法声明???的类型

// 从C++ 11开始添加了一个新的关键字decltype用来解决上面的问题, decltype 是“declare type”的缩写，译为"声明类型"
// 使用decltype(x)来声明这个类型,x可以是表达式

// 上面的就可以更改为
template <typename T1, typename T2>
void AddTo(T1, T2)
{
    // decltype(T1 + T2) T_temp;       // 这句话的意思是使T_temp的类型,与 T1 + T2 的类型相同
    // T_temp = T1 + T2;

    // 上面两句可以缩写
    decltype(T1 + T2) T_temp = T1 + T2;
    return T_temp;
}

// 1. 如果decltype中的类型是一个没有使用括号的标识符,类似于: decltype(x) var,那么 var 的类型与 x 的类型相同
// 2. 如果decltype中的类型是一个函数调用,类似:decltype(function(x)) var,那么var 的类型与函数声明中的返回值类型相同
//     注意: decltype不会调用函数,编译器通过查看函数原型来查看函数返回值类型
// 3. 如果decltype中的类型是一个使用了括号的标识符,类似:decltype((x)) var,x是一个左值,那么 var 的类型将会为指向这个类型的引用

int main()
{
    int j = 3;
    int &k = j;
    int &n = j;
    decltype(j + 6) i1; // i1 为 int类型
    decltype(k + n) i2; // i2 为 int类型,因为k+n是一个表达式
    decltype(100L) i3;  // i3 为 long类型

    // 如果需要重复声明一种类型,可以配合typedef来使用
    typedef decltype(k + n) declK_N;
    declK_N decl1;
    declK_N declArray[10];
    declK_N &declRef = declArray[0];

    return 0;
}

// 如果想要使用返回值作为decltype类型, C++11 新增了一种语法叫做 "后置返回值类型"
// 他与普通的函数原型相同,只是他可以声明返回值为decltype类型的函数

// 普通函数
double target(int x, float y);
// 后置返回值声明
auto target(int x, float y) -> double;

// 加上decltype
template <class T1, class T2>
auto target(T1 x, T2 y) -> decltype(x + y)
{
    return x + y;
}
